package util

import (
	"errors"
	"fmt"
	"io"
	"net"
	"net/http"
	"strings"
	"time"

	"github.com/shirou/gopsutil/cpu"
	"github.com/shirou/gopsutil/disk"
	"github.com/shirou/gopsutil/host"
	"github.com/shirou/gopsutil/load"
	"github.com/shirou/gopsutil/mem"
	gnet "github.com/shirou/gopsutil/net"
)

type CpuState struct {
	ID        int32
	Name      string
	Cores     int32
	ModelName string
	Mhz       float64
}

type MemState struct {
	Category    string
	Total       string
	Available   string
	UsedPercent int
}

type DiskState struct {
	Path        string
	Fstype      string
	Total       string
	Free        string
	UsedPercent int
}

type HostState struct {
	Hostname        string
	BootTime        string
	OS              string
	Platform        string
	PlatformFamily  string
	PlatformVersion string
	KernelVersion   string
	KernelArch      string
	InternalIP      string
	ExternalIP      string
}

type ServiceState struct {
	Name    string
	Version string
	State   string
}

func GetMemInfo() []MemState {
	v, _ := mem.VirtualMemory()
	vm := MemState{Category: "物理内存", Total: formatByteSize(v.Total), Available: formatByteSize(v.Available), UsedPercent: int(v.UsedPercent)}
	s, _ := mem.SwapMemory()
	sm := MemState{Category: "交换内存", Total: formatByteSize(s.Total), Available: formatByteSize(s.Free), UsedPercent: int(s.UsedPercent)}
	return []MemState{vm, sm}
}

//formatFileSize 字节的单位转换 保留两位小数
func formatByteSize(fileSize uint64) (size string) {
	if fileSize < 1024 {
		//return strconv.FormatInt(fileSize, 10) + "B"
		return fmt.Sprintf("%.2f B", float64(fileSize)/float64(1))
	} else if fileSize < (1024 * 1024) {
		return fmt.Sprintf("%.2f KB", float64(fileSize)/float64(1024))
	} else if fileSize < (1024 * 1024 * 1024) {
		return fmt.Sprintf("%.2f MB", float64(fileSize)/float64(1024*1024))
	} else if fileSize < (1024 * 1024 * 1024 * 1024) {
		return fmt.Sprintf("%.2f GB", float64(fileSize)/float64(1024*1024*1024))
	} else if fileSize < (1024 * 1024 * 1024 * 1024 * 1024) {
		return fmt.Sprintf("%.2f TB", float64(fileSize)/float64(1024*1024*1024*1024))
	} else { //if fileSize < (1024 * 1024 * 1024 * 1024 * 1024 * 1024)
		return fmt.Sprintf("%.2f EB", float64(fileSize)/float64(1024*1024*1024*1024*1024))
	}
}

// cpu info
func GetCpuInfo() []CpuState {
	cpuInfos, err := cpu.Info()
	if err != nil {
		return nil
	}
	var css []CpuState

	for _, ci := range cpuInfos {
		cs := CpuState{ID: ci.CPU, Name: ci.VendorID, Cores: ci.Cores, ModelName: ci.ModelName, Mhz: ci.Mhz}
		css = append(css, cs)
	}
	return css
}

//GetCpuLoad CPU负载
func GetCpuLoad() {
	info, _ := load.Avg()
	fmt.Printf("%v\n", info)
}

//GetHostInfo host info
func GetHostInfo() HostState {
	h, _ := host.Info()
	return HostState{
		Hostname:        h.Hostname,
		BootTime:        time.Unix(int64(h.BootTime), 0).Format("2006-01-02 15:04:05"),
		OS:              h.OS,
		Platform:        h.Platform,
		PlatformFamily:  h.PlatformFamily,
		PlatformVersion: h.PlatformVersion,
		KernelVersion:   h.KernelVersion,
		KernelArch:      h.KernelArch,
		InternalIP:      GetAInternalIP(),
		ExternalIP:      GetAExternalIP()}
}

//GetDiskInfo 获取磁盘信息
func GetDiskInfo() []DiskState {
	parts, err := disk.Partitions(true)
	if err != nil {
		return nil
	}
	var dss []DiskState
	for _, part := range parts {
		diskInfo, _ := disk.Usage(part.Mountpoint)
		ds := DiskState{Path: diskInfo.Path, Fstype: part.Fstype, Total: formatByteSize(diskInfo.Total), Free: formatByteSize(diskInfo.Free), UsedPercent: int(diskInfo.UsedPercent)}
		dss = append(dss, ds)
	}
	return dss
}

func GetAInternalIP() string {
	ip, _ := GetInternalIP()
	return ip
}

func GetAExternalIP() string {
	ip, _ := GetExternalIP()
	return ip
}

//GetInternalIP 获取内网IP地址
func GetInternalIP() (string, error) {
	// 思路来自于Python版本的内网IP获取，其他版本不准确
	conn, err := net.Dial("udp", "8.8.8.8:80")
	if err != nil {
		return "", errors.New("internal IP fetch failed, detail:" + err.Error())
	}
	defer conn.Close()

	// udp 面向无连接，所以这些东西只在你本地捣鼓
	res := conn.LocalAddr().String()
	res = strings.Split(res, ":")[0]
	return res, nil
}

//GetExternalIP 获取外网IP地址
func GetExternalIP() (string, error) {
	// 有很多类似网站提供这种服务，这是我知道且正在用的
	// 备用：https://myexternalip.com/raw （cip.cc 应该是够快了，我连手机热点的时候不太稳，其他自己查）
	response, err := http.Get("http://ip.cip.cc")
	if err != nil {
		response, err = http.Get("https://myexternalip.com/raw")
		if err != nil {
			return "", errors.New("external IP fetch failed, detail:" + err.Error())
		}
	}
	defer response.Body.Close()
	res := ""

	// 类似的API应当返回一个纯净的IP地址
	for {
		tmp := make([]byte, 32)
		n, err := response.Body.Read(tmp)
		if err != nil {
			if err != io.EOF {
				return "", errors.New("external IP fetch failed, detail:" + err.Error())
			}
			res += string(tmp[:n])
			break
		}
		res += string(tmp[:n])
	}

	return strings.TrimSpace(res), nil
}

//GetNetInfo
func GetNetInfo() {
	info, _ := gnet.IOCounters(true)
	for index, v := range info {
		fmt.Printf("%v:%v send:%v recv:%v\n", index, v, v.BytesSent, v.BytesRecv)
	}
}

func GetSysService() []ServiceState {
	return []ServiceState{GetDockerSerivce(), GetNginxService()}
}

func GetDockerSerivce() ServiceState {
	return ServiceState{Name: "Docker", Version: "-", State: "未安装"}
}

func GetNginxService() ServiceState {
	return ServiceState{Name: "Nginx", Version: "-", State: "未安装"}
}
